using System;
using Rogan.Utility.Common;

namespace Rogan.Data
{
    /// <summary>
    /// Where Expression
    /// </summary>
    [Serializable]
    public class WhereExpression : IDbExpression, ICloneable<WhereExpression>, ITableResetable
    {
        /// <summary>
        /// Where
        /// </summary>
        public DbExpressionType ExpressionType
        {
            get
            {
                return DbExpressionType.Where;
            }
        }
        /// <summary>
        /// Left Expression
        /// </summary>
        public WhereExpression Left
        {
            get;
            set;
        }

        /// <summary>
        /// Right Expression
        /// </summary>
        public WhereExpression Right
        {
            get;
            set;
        }

        /// <summary>
        /// Left Field
        /// </summary>
        public Field LeftField
        {
            get;
            set;
        }

        /// <summary>
        /// Right Field
        /// </summary>
        public Field RightField
        {
            get;
            set;
        }

        /// <summary>
        /// Expression Value
        /// </summary>
        public object Value
        {
            get;
            set;
        }

        /// <summary>
        /// Sub Expression
        /// </summary>
        public EntityQueryExpression SubExpression
        {
            get;
            set;
        }
        public WhereExpression Quote
        {
            get;
            set;
        }
        public QueryOperator Operator
        {
            get;
            set;
        }

        internal bool? IsAll
        {
            get;
            set;
        }
        public bool IsSingle
        {
            get
            {
                return Left == null && Right == null;
            }
        }
        public static WhereExpression All
        {
            get
            {
                return new WhereExpression
                {
                    IsAll = true
                };
            }
        }
        public WhereExpression Not
        {
            get
            {
                return new WhereExpression
                {
                    Quote = this,
                    Operator = QueryOperator.BitwiseNOT
                };
            }
        }
        public static bool IsNullOrEmpty(WhereExpression exp)
        {
            return exp == null || (Equals(exp.Left, null) && Equals(exp.Right, null) && Equals(exp.LeftField, null) && Equals(exp.RightField, null));
        }
        public static WhereExpression Create(WhereExpression left, WhereExpression right, QueryOperator op)
        {
            return new WhereExpression
            {
                Left = left,
                Right = right,
                Operator = op
            };
        }
        public static WhereExpression Create(Field leftField, Field rightField, QueryOperator op)
        {
            return new WhereExpression
            {
                LeftField = leftField,
                RightField = rightField,
                Operator = op
            };
        }
        public static WhereExpression Create(Field leftField, object value, QueryOperator op)
        {
            WhereExpression whereExpression = new WhereExpression
            {
                LeftField = leftField,
                Operator = op
            };
            if (value is IEntityQueryable)
            {
                whereExpression.SubExpression = ((IEntityQueryable)value).Expression;
            }
            else
            {
                if (value is EntityQueryExpression)
                {
                    whereExpression.SubExpression = (EntityQueryExpression)value;
                }
                else
                {
                    whereExpression.Value = value;
                    if (whereExpression.Value == null && whereExpression.Operator == QueryOperator.Equal)
                    {
                        whereExpression.Operator = QueryOperator.IsNULL;
                    }
                    if (whereExpression.Value == null && whereExpression.Operator == QueryOperator.NotEqual)
                    {
                        whereExpression.Operator = QueryOperator.IsNotNULL;
                    }
                }
            }
            return whereExpression;
        }
        public static WhereExpression Create(object value, Field rightField, QueryOperator op)
        {
            WhereExpression whereExpression = new WhereExpression
            {
                RightField = rightField,
                Value = value,
                Operator = op
            };
            if (value is IEntityQueryable)
            {
                whereExpression.SubExpression = ((IEntityQueryable)value).Expression;
            }
            else
            {
                if (value is EntityQueryExpression)
                {
                    whereExpression.SubExpression = (EntityQueryExpression)value;
                }
            }
            return whereExpression;
        }

        public static WhereExpression operator &(WhereExpression left, WhereExpression right)
        {
            return Create(left, right, QueryOperator.And);
        }
        public static WhereExpression operator |(WhereExpression left, WhereExpression right)
        {
            return Create(left, right, QueryOperator.Or);
        }
        public static bool operator true(WhereExpression exp)
        {
            return false;
        }
        public static bool operator false(WhereExpression exp)
        {
            return false;
        }
        public WhereExpression Clone()
        {
            return DataHelper.Clone(this) as WhereExpression;
        }
        public void SetTable(string tName)
        {
            if (LeftField != null)
            {
                LeftField.SetTableName(tName);
            }
            if (RightField != null)
            {
                RightField.SetTableName(tName);
            }
            if (Left != null)
            {
                Left.SetTable(tName);
            }
            if (Right != null)
            {
                Right.SetTable(tName);
            }
        }
    }
}
